/*
 * Process.h
 *
 *  Created on: Sep 19, 2018
 *      Author: ax
 */

#ifndef _SOS_Process_H_
#define _SOS_Process_H_

#include <Timer.h>
#include <Error.h>
#include <System.h>


#define Process_INVALID            ((Process_Id) 0)


typedef enum {//!!!DONOT REORDER BELOWS UNLESS YOU ARE CLEAR ENOUGH!!!
    Process_DELAY           = 1 << 0,   //a time while
    Process_SLEEP           = 1 << 1,   //tick
    Process_PEND            = 1 << 2,
    Process_PEND_FOREVER,
    Process_SUSPEND         = 1 << 3,  //non Process_READY attribute specified created progress will be put in suspended queue
    #define Process_RESUME (0 << 3)
    Process_READY           = 1 << 4,   //ready to run

    Process_BE_CUT          = 1 << 5,
    Process_CUT             = 1 << 6,   //progress will have same status with progress be cut with.
    Process_CUT_BEFORE      = Process_CUT,
    Process_CUT_AFTER,
    Process_CUT_NEXT_N,
    #define Process_CUT_INVOLVED (Process_CUT | Process_BE_CUT)

    Process_NON_BREAKABLE   = 1 << 7,
    #define Process_BREAKABLE (0 << 7)

    Process_HAS_ARGS        = 1 << 8,
    Process_HAS_RETURN      = 1 << 9,
    #define Process_SIMPLE   (0)
    #define Process_STD     (Process_HAS_ARGS + Process_HAS_RETURN)

    /********/

    Process_HAS_ENV        = 1 << 15,

    //Return code (RC)
    Process_SOK = 0,
    Process_RETURN_START = Sos_Progress << ERROR_MODULE_SHIFT,//STATUS(Sos_Progress, 0)
    Process_EMPTY_LOOP,
    Process_NOT_AVILABLE,
    Process_ADD_STATUS_ABOVE____TODO__,

    Process_Status_MAX_ABOVE
} Process_Status;

typedef Process_Status (*Process)(int argc, void* argv[]);
#define Process_SELF                Process_getSelfId()
#define Process_getIdByName(NAME)   Process_##NAME


//Macros fro XXX
#define Process_ID_DEFINE(NAME)     Process_Id Process_getIdByName(NAME)
#define Process_ID_DECLARE(NAME)    extern Process_Id Process_getIdByName(NAME)

#ifndef _SOS_VAR_DEFINITION_
#define PROC_ID(NAME)               Process_ID_DECLARE(NAME)
#else
#define PROC_ID(NAME)               Process_ID_DEFINE(NAME)
#endif

#define PROC_SIMPLE(PROC)           extern void PROC(void)
#define PROC_NO_ARGS(PROC)          extern Process_Status PROC(void)
#define PROC_NO_RETURN(PROC)        extern void PROC(int argc, void* argv[])
#define PROC_STD(PROC)              extern Process_Status PROC(int argc, void* argv[])

#define Process_AddSimple(name, prog, priority, sts) \
    do { \
        Process_getIdByName(UdpD) \
            = Process_create((Progress) UdpD, priority, 0, NULL, sts); \
    } while 0

#define Process_AddStd(name, prog, priority, argc, argv, sts) \
    do { \
        Process_getIdByName(UdpD) \
            = Process_create((Progress) UdpD, priority, argc, argv, sts); \
    } while 0

//Hook support may need
typedef int (*Hook)();

typedef struct {
    Hook init;
    Hook run;
    Hook _return;
    Hook suspend;
    Hook exit;
} Process_Hooks;

/* ==============VAR============== */
extern const Sid Process_SupportCount;

/* ==============API============== */
extern
Process_Id
Process_create(
    Process         prog,
    Priority        priority,
    int             argc,
    void*           argv[],
    Process_Status  nextStatus  //Process_RUNNING to start immediately, others
);


extern
Process_Status
Process_cut(                //pid associated progress will cut the schedule queue
    Process_Id      pid,    //the queue jumper
    Process_Status  action, //identifier the cut action, valid for {Process_CUT_BEFORE,Process_CUT_AFTER,Process_CUT_NEXT_N}
    Process_Id      parameter//be cut progress or the count for Process_CUT_NEXT_N
);

extern
Process_Status
Process_suspend(    //Resume pid associated progress from (mainly in) ready to suspend
    Process_Id  pid
);

extern
Process_Status
Process_resume(     //Resume pid associated progress from (mainly in) suspend to ready
    Process_Id  pid
);

extern
void
Process_nop(        //Nop at least nano_second, no interrupt safe.
    NanoSecond  ns
);

extern
void
Process_redirect(
    Process_Id  pid,
    Process     prog,
    int         argc,
    void*       argv
);

extern
Process_Id
Process_getSelfId(void);

static inline
Uint32
Process_name(
    char a,
    char b,
    char c,
    char d
){
    Union32 var;
    var.Byte[0] = a;
    var.Byte[1] = b;
    var.Byte[2] = c;
    var.Byte[3] = d;

    return var.QByte;
}


#endif /* _SOS_Process_H_ */
